package com.csaba.swing;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;

import com.csaba.swing.action.AccountOverviewAction;
import com.csaba.swing.action.ActionFactory;
import com.csaba.swing.action.ChangePasswordAction;
import com.csaba.swing.action.ExitAction;
import com.csaba.swing.action.InitEncryptionAction;
import com.csaba.swing.action.LoginAction;
import com.csaba.swing.action.LogoutAction;
import com.csaba.swing.action.PreferencesAction;
import com.csaba.swing.action.SessionListAction;
import com.csaba.swing.action.SetPasswordAction;
import com.csaba.swing.action.TransactionFilterAction;
import com.csaba.swing.gui.GUIContext;
import com.csaba.swing.gui.InitStoreDialog;
import com.csaba.swing.gui.SetPasswordDialog;
import com.csaba.swing.gui.StatusBar;
import com.csaba.swing.gui.util.GUIUtil;
import com.csaba.swing.gui.util.WindowSizeContanier;
import com.csaba.swing.model.Config;
import com.csaba.util.I18N;
import com.csaba.util.LoggerHelper;
import com.csaba.util.encryption.EncryptedStore;

/**
 * This is a SWING based service browser, and GUI for testing the service.
 * 
 * Pending extensions:
 * <ul>
 * <li>TODO Money transfer functions</li>
 * <li>TODO Account balance tagging</li>
 * <li>TODO Sending dummy requests to keep session alive. (15 sec for CIB.)</li>
 * </ul>
 * 
 * @author Gabe
 */
public final class MainWindow
{
	private final static Logger logger = LoggerHelper.getDefaultLogger();

	public final static MainWindow I18N_NAMESPACE = new MainWindow();

	private static JFrame frame;
	private static JDesktopPane desktop;
	private static StatusBar statusBar;

	private MainWindow()
	{
		//do not instantiate this class from outside.
	}

	/**
	 * @param args
	 */
	public static void main( final String[] args )
	{
		//init logger
		LoggerHelper.initLogger(Level.INFO);

		initConfig();

		//init user.agent system property for HTTP based connectors
		System.setProperty("user.agent", I18N.getString(I18N_NAMESPACE, "MainWindow.userAgent")); //$NON-NLS-1$ //$NON-NLS-2$
		logger.fine("Setting user agent to: " + System.getProperty("user.agent")); //$NON-NLS-1$ //$NON-NLS-2$

		//set a few Swing properties
		JFrame.setDefaultLookAndFeelDecorated(true);
		JDialog.setDefaultLookAndFeelDecorated(true);

		initFrame();

		initEncryptionStore();

		ActionFactory.getAction(LoginAction.class).actionPerformed(null);
	}

	private static void initEncryptionStore()
	{
		//init EncryptionStore

		if ( Config.getInstance().isOpenOnStartup() )
		{
			if ( !EncryptedStore.getInstance().isInitialized() )
			{
				logger.fine("EncryptionStore is not yet initialized."); //$NON-NLS-1$
				new InitStoreDialog(frame).setVisible(true);
			}
			else if ( !EncryptedStore.getInstance().isOpen() )
			{
				logger.fine("EncryptionStore is not yet open."); //$NON-NLS-1$
				new SetPasswordDialog(frame).setVisible(true);
			}
		}
		EncryptedStore.getInstance().debugKeys(Level.FINE);
	}

	private static void initFrame()
	{
		frame = new JFrame(I18N.getString(I18N_NAMESPACE, "MainWindow.title")); //$NON-NLS-1$
		frame.addWindowListener(new WindowAdapter()
		{

			@Override
			public void windowClosing( final WindowEvent event )
			{
				ActionFactory.getAction(ExitAction.class).actionPerformed(null);
			}

		});

		//build base menu
		final JMenuBar menuBar = new JMenuBar();

		final JMenu sessionMenu = new JMenu(I18N.getString(I18N_NAMESPACE, "MainWindow.menu.session")); //$NON-NLS-1$
		GUIUtil.setMnemonic(sessionMenu);
		menuBar.add(sessionMenu);

		sessionMenu.add(new JMenuItem(ActionFactory.getAction(LoginAction.class)));
		sessionMenu.add(new JMenuItem(ActionFactory.getAction(LogoutAction.class)));
		sessionMenu.add(new JMenuItem(ActionFactory.getAction(SessionListAction.class)));
		sessionMenu.addSeparator();
		sessionMenu.add(new JMenuItem(ActionFactory.getAction(ExitAction.class)));

		final JMenu accountMenu = new JMenu(I18N.getString(I18N_NAMESPACE, "MainWindow.menu.accounts")); //$NON-NLS-1$
		GUIUtil.setMnemonic(accountMenu);
		menuBar.add(accountMenu);

		accountMenu.add(new JMenuItem(ActionFactory.getAction(AccountOverviewAction.class)));
		accountMenu.add(new JMenuItem(ActionFactory.getAction(TransactionFilterAction.class)));

		final JMenu toolsMenu = new JMenu(I18N.getString(I18N_NAMESPACE, "MainWindow.menu.tools")); //$NON-NLS-1$
		GUIUtil.setMnemonic(toolsMenu);
		menuBar.add(toolsMenu);

		toolsMenu.add(new JMenuItem(ActionFactory.getAction(InitEncryptionAction.class)));
		toolsMenu.add(new JMenuItem(ActionFactory.getAction(SetPasswordAction.class)));
		toolsMenu.add(new JMenuItem(ActionFactory.getAction(ChangePasswordAction.class)));
		toolsMenu.addSeparator();
		toolsMenu.add(new JMenuItem(ActionFactory.getAction(PreferencesAction.class)));

		//create toolbar
		final JToolBar toolbar = new JToolBar(I18N.getString(I18N_NAMESPACE, "MainWindow.toolbar.title")); //$NON-NLS-1$

		toolbar.add(createToolbarButton(LoginAction.class));
		toolbar.add(createToolbarButton(LogoutAction.class));
		toolbar.add(createToolbarButton(SessionListAction.class));
		toolbar.addSeparator();
		toolbar.add(createToolbarButton(AccountOverviewAction.class));
		toolbar.add(createToolbarButton(TransactionFilterAction.class));
		toolbar.addSeparator();
		toolbar.add(createToolbarButton(ExitAction.class));

		desktop = new JDesktopPane();

		final ImageIcon icon = GUIContext.getImage("csaba_wonder"); //$NON-NLS-1$
		if ( icon != null )
		{
			final JLabel label = new JLabel(icon);
			label.setBounds(0, 0, icon.getIconWidth(), icon.getIconHeight());
			desktop.add(label, Integer.MIN_VALUE);
			desktop.addComponentListener(new ComponentListener()
			{

				@Override
				public void componentHidden( final ComponentEvent arg0 )
				{
				}

				@Override
				public void componentMoved( final ComponentEvent arg0 )
				{
				}

				@Override
				public void componentResized( final ComponentEvent arg0 )
				{
					final Component comp = (Component) arg0.getSource();
					final Dimension dim = comp.getSize();
					label.setLocation(dim.width - icon.getIconWidth() - 5, dim.height - icon.getIconHeight() - 5);
				}

				@Override
				public void componentShown( final ComponentEvent arg0 )
				{
				}
			});
		}

		statusBar = new StatusBar();

		frame.setJMenuBar(menuBar);
		final Container content = frame.getContentPane();
		content.setLayout(new BorderLayout());
		content.add(toolbar, BorderLayout.PAGE_START);
		content.add(desktop, BorderLayout.CENTER);
		content.add(statusBar, BorderLayout.SOUTH);

		if ( !WindowSizeContanier.getInstance().monitorComponent(frame) )
			frame.setSize(800, 550);
		frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		frame.setVisible(true);
	}

	private static void initConfig()
	{
		try
		{
			Config.loadConfig();
		}
		catch ( final Exception e )
		{
			logger.warning("Error loading config: " + e); //$NON-NLS-1$
			try
			{
				//create config if it is not found
				Config.saveConfig();
			}
			catch ( final Exception e1 )
			{
				logger.log(Level.SEVERE, "Error creating config file.", e1); //$NON-NLS-1$
			}
		}
	}

	private static JButton createToolbarButton( final Class<?> actionClass )
	{
		final Action action = ActionFactory.getAction(actionClass);
		final JButton button = new JButton(action);
		if ( action.getValue(Action.LARGE_ICON_KEY) != null )
			button.setHideActionText(true);
		return button;
	}

	public static JDesktopPane getDesktop()
	{
		return desktop;
	}

	public static JFrame getFrame()
	{
		return frame;
	}

	public static StatusBar getStatusBar()
	{
		return statusBar;
	}

	public static String getString( final String key )
	{
		return I18N.getString(I18N_NAMESPACE, key);
	}

	public static String getString( final String key, final Object... arguments )
	{
		return I18N.getString(I18N_NAMESPACE, key, arguments);
	}

}
